'''
Created on Jun 11, 2010

@author: Joshua, Bill
'''

import csv

from core.models import WebcamMeta, Webcam
from django.db import connection, transaction

tagged_tag = "tagged"

#Only used in parse_post(post)
known_tags = set(["people", "street", "intersection", "bikelane", "sidewalk", "trafficlight", "crosswalk", "buildings", "shade", "grass", "trees", "plaza", "bench", "fountain", "water", "park", "school", "snow", "mountain", "skiarea"])

# the old tags used for the old mturk
old_tags = set(["grass", "trees", "rivers", "lakes", "ocean", "mountains", "sky", "clouds", "people", "cars", "road", "parkinglots", "buildings"])

# tags we don't want from the old tags, this is just a subset of old_tags
bad_tags = set(["grass", "trees", "rivers", "lakes", "ocean", "mountains", "people", "cars", "road", "parkinglots", "buildings", "tagged", "/view/index.shtml"])

def parse_post(post):
    tag_set = set()
    for tag in known_tags:
        if post.get(tag, False):
            tag_set.add(tag)
    return tag_set

def majority(bools):
    '''
        Returns True if more than half of the inputs are true.
        Otherwise, returns False.
    '''
    count = sum(bools, 0) #True = 1, False = 0
    return count > (len(bools) / 2.0)

def combine_answers(answers, method, default_value = False):
    '''
        Combines a list of dictionaries into one dictionary.

        Returns a new dict consisting of one key-value pair for
        each key in the first dict in answers. Each value is
        the result of calling the supplied method on the list of
        values for that key across every dictionary in answers.
        If a key is missing from a dictionary other than the first,
        it is assumed to be the supplied default_value (normally
        False).
    '''
    combo_answer = {}
    for key in answers[0].keys():
        bools = [answer.get(key, False) for answer in answers]
        combo_answer[key] = method(bools)
    return combo_answer

def read_dicts(res_readers):
    '''
        Creates a map of tagging results from the supplied CSV file.

        The returned object is a dictionary, with camera IDs as keys,
        to a list of tagging results, one line per entry in the CSV
        files with that particular camera ID.
    '''
    res_dict = {}
    for res_reader in res_readers:
        for line in res_reader:
            if line["assignmentstatus"] == "Rejected":
                continue #Don't read rejected submissions.

            cid = int(line["annotation"]) # Camera ID is annotation.
            list = res_dict.get(cid, None)
            if list is None:
                list = []
                res_dict[cid] = list

            map = {}
            for key, val in line.iteritems():
                # we need all the answers, plus workerid
                if key.startswith("Answer.") or key.startswith('workerid'):
                    #if key in known_tags:
                    map[key] = val
            list.append(map)
    return res_dict

def add_tags(meta, dict):
    tag_set = meta.get_tags()
    tag_set -= known_tags #Only the POST'd known_tags should remain.
    tag_set |= parse_post(dict)

    meta.set_tags(tag_set)
    meta.save() #Commit changes.

def import_tags(files, method = any, commit = True):
    '''
        Imports the tags from the CSV files into the camera database.

        Opens each supplied file, reads in the information with
        read_dicts(res_readers), and adds the resultant tags to
        their respective cameras. Returns the QuerySet of cameras
        whose IDs were found in the files. Automatically saves
        each camera unless the optional argument commit is set
        to false.
    '''
    res_dicts = {}
    try:
        res_files = [open(file, "rb") for file in files]
        res_readers = [csv.DictReader(res_file, dialect=csv.excel_tab)
                       for res_file in res_files]
        res_dicts = read_dicts(res_readers)
    finally:
        if res_files:
            for res_file in res_files:
                res_file.close()

    cam_tags = dict( \
        (cid, combine_answers(answers, method))
        for cid, answers in res_dicts.iteritems())

    #Grab all of the cams we have ids for.
    cams = WebcamMeta.objects.filter(webcam__id__in=set(cam_tags.keys()))

    for cam in cams:
        tag_set = cam.get_tags()
        for key, val in cam_tags[cam.webcam.id].iteritems():
            if val:
                tag_set.add(key)
        tag_set.add(tagged_tag) #Tag'd!
        cam.set_tags(tag_set)

        if commit: #or (commit is None and import_tags.commit):
            cam.save() #Commit changes.

    return cams

def read_results():
    import os

    path = 'static/mturk/results/'
    listing = ['%s%s'%(path,item) for item in os.listdir(path)]
    res_dicts = {}
    res_files = []
    try:
        res_files = [open(fn, "rb") for fn in listing]
        res_readers = [csv.DictReader(res_file, dialect=csv.excel_tab)
                       for res_file in res_files]
        res_dicts = read_dicts(res_readers)
    finally:
        if res_files:
            for res_file in res_files:
                res_file.close()

    return res_dicts

def batch_untag(output_fn='untagged_cams.txt'):
    cursor = connection.cursor()
    qs = """SELECT id FROM core_webcam"""
    cursor.execute(qs)
    webcam_data = cursor.fetchall()
    
    ids = []
    for data in webcam_data:
        ids.append(data[0])
    
    count = 0
    f = open(output_fn,'wb') # we should probably backup the cams and their tags we messed with    
    for id in ids:
        if (id >= 1000) and (id % 10 == 0):
            webcam = Webcam.objects.get(id=id)
            try:
                meta = WebcamMeta.objects.get(webcam=webcam)
            except:
                continue
            if (meta is not None) and (meta.tags is not None) and ('tagged' in meta.tags):
                tags = meta.get_tags()
                f.write('%s;%s\n'%(id, meta.tags))    
                tags -= bad_tags
                meta.set_tags(tags)
                meta.save()
                count += 1
    f.close()
    print "Untagged %s cams from database, untagged cams backed up in %s" %(count, output_fn)
    
